package com.test.lucene.index;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.test.lucene.LuceneException;

/**
 * Will handle the retry logic for delete and update operations.
 * 
 * @author Patrick Kimber
 * 
 */
final class RetryHandler {

    /** Retry count in the case of a lock or stale writer. */
    private static final int RETRY_COUNT = 60;

    /** Length of time to sleep before retrying the operation. */
    private static final int RETRY_SLEEP = 1000;

    /** Standard logger. */
    private final Log logger = LogFactory.getLog(RetryHandler.class);

    /** The retry count. */
    private int count = 0;

    /** Name of the class we are handling retry events for. */
    private String className;

    /**
     * Constructor.
     * 
     * @param name
     *            The name of the class we are handling retry events for.
     */
    public RetryHandler(final String name) {
        setClassName(name);
        if (logger.isDebugEnabled()) {
            logger.debug("RetryHandler(" + getClassName() + ")");
        }
    }

    /**
     * Should the operation be retried?
     * 
     * @param thrown
     *            The exception which was thrown by the last operation.
     * @return <code>true</code> if the operation should be retried.
     * @throws LuceneException
     *             If the retry count is exceeded.
     */
    public boolean retry(final Exception thrown) throws LuceneException {
        incrementCount();
        if (thrown == null) {
            return false;
        } else {
            if (getCount() >= RETRY_COUNT) {
                logger
                        .error(getClassName() + ". Retry count exceeded.",
                                thrown);
                throw new LuceneException(getClassName()
                        + ". Retry count exceeded.", thrown);
            } else {
                if (logger.isDebugEnabled()) {
                    logger.debug(getClassName() + ". retry(" + getCount()
                            + ", " + thrown.getClass().getName() + ")");
                }
                // TODO Remove this print statement...
                System.out.print(".");
                sleep(thrown);
                return true;
            }
        }
    }

    /**
     * Sleep until the next retry.
     * 
     * @param thrown
     *            The exception which was thrown by the last operation.
     * @throws LuceneException
     *             If the sleep is interrupted.
     */
    private void sleep(final Exception thrown) throws LuceneException {
        try {
            Thread.sleep(RETRY_SLEEP);
        } catch (InterruptedException e) {
            throw new LuceneException(getClassName() + ". Retry interrupted.",
                    thrown);
        }
    }

    /** @return the count. */
    int getCount() {
        return count;
    }

    /** Increment the count. */
    private void incrementCount() {
        ++count;
    }

    /** @return the className. */
    private String getClassName() {
        return className;
    }

    /**
     * @param value
     *            Set the className.
     */
    private void setClassName(final String value) {
        className = value;
    }
}
